﻿//////////////////////////////////////////////////////////////////////////////////////////
// WidgetLibrary - is free library to run HTML5 Widget app on Windows Phone 7           //
// Copyright 2011-2012  daenet GmbH Frankfurt am Main                                                               //
//                                                                                      //
// This code is free software under the GNU Library General Public License (LGPL)       //
// See licence section of  http://wpwidgetlibrary.codeplex.com/license                  //
//                                                                                      //
//
////////////////////////////////////////////////////////////////////////////////////////// 
using System;
using System.Linq;
using System.IO.IsolatedStorage;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Collections.Generic;

namespace Daenet.WidgetLibrary
{
    /// <summary>
    /// Class is used to extract HTML content from the application resource and use as regular HTML Widget app.
    /// </summary>
    /// <remarks>For more information go to http://wpwidgetlibrary.codeplex.com </remarks>
    public class WPWidgetLibrary
    {

        #region Fields
        private List<string> m_Subfolders = new List<string>();
        #endregion

        #region Public Methods
        /// <summary>
        /// Extract all HTML related content from embedded resources and copy it to Isolated Storage.  
        /// </summary>
        /// <param name="htmlFolder"></param>
        /// <param name="htmlDirs"></param>
public void InstalHTMLContent(string htmlFolder, string[] htmlDirs)
{
    if (htmlDirs == null)
        throw new Exception("No html folder structure passed!");

    //First we have to load HTML content first time App is running or deployed
    if (!IsFirstTimeRun())
        return;

    Debug.WriteLine("Application runs for the first time!");

    //Fistr resolve folder structure of HTML app
    resolveSubfolders(htmlDirs);

    var asm = Assembly.GetCallingAssembly();

    using (IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())
    {
        deleteDirectory(isolatedStorageFile, String.Empty);

        foreach (var webResource in asm.GetManifestResourceNames())
        {
            if (iswebResource(webResource))
            {
                var pos = webResource.ToLower().IndexOf(htmlFolder.ToLower());
                if (pos > 0)
                    copyFile(isolatedStorageFile, getFileNameFromResourceName(webResource.Substring(0, pos + htmlFolder.Length + 1), webResource), asm.GetManifestResourceStream(webResource));
                else
                    throw new InvalidOperationException("invalid resource name.");
            }
        }
    }
}

        #endregion

        #region Private Methods
        /// <summary>
        /// Check is file is in corect file format
        /// </summary>
        /// <param name="webResource"></param>
        /// <returns></returns>
        private bool iswebResource(string webResource)
        {
            var tokens = webResource.Split('.');
            if (IsWebExtension(tokens[tokens.Length - 1]))
                return true;
            else
                return false;
        }

        /// <summary>
        /// We can include some specific file-extension to be a part of HTML app.
        /// If you have some other files like HTC wjich we didn't include just override this method.
        /// </summary>
        /// <param name="ext"></param>
        /// <returns></returns>
        protected virtual bool IsWebExtension(string ext)
        {
            bool res = false;

            switch (ext.ToLower())
            {
                case "htm":
                case "html":
                case "js":
                case "jpg":
                case "jpeg":
                case "png":
                case "css":

                    res = true;
                    break;
            }

            return res;
        }

        /// <summary>
        /// Small helper to xtract name from full resource W7 name.
        /// </summary>
        /// <param name="assemblyReplacement"></param>
        /// <param name="webResource"></param>
        /// <returns></returns>
        private string getFileNameFromResourceName(string assemblyReplacement, string webResource)
        {
            return webResource.Replace(assemblyReplacement, "");
        }


        /// <summary>
        /// This is copying files from installed to isolatedstorage target location 
        /// </summary>
        /// <param name="isoFile"></param>
        /// <param name="webResourceFileName"></param>
        /// <param name="webResourceStream"></param>
        private void copyFile(IsolatedStorageFile isoFile, string webResourceFileName, Stream webResourceStream)
        {
            const int BUFFSIZE = 1024;

            webResourceFileName = createRequiredDirectory(isoFile, webResourceFileName);

            using (IsolatedStorageFileStream isoFileStream = isoFile.OpenFile(webResourceFileName, FileMode.Create))
            {
                byte[] buffer = new byte[BUFFSIZE];
                int readBytes;
                do
                {
                    readBytes = webResourceStream.Read(buffer, 0, buffer.Length);
                    isoFileStream.Write(buffer, 0, readBytes);
                }
                while (readBytes > 0);
                isoFileStream.Flush();
                isoFileStream.Close();
            }

            Debug.WriteLine("File \"" + webResourceFileName + "\" copied to app storage location.");
        }

        /// <summary>
        /// Creates the list of all subfolders from specified array.
        /// Creates from "aa/bb/cc following entries in m_Subfolders:
        /// aa
        /// aa/bb
        /// aa/bb/cc 
        /// </summary>
        /// <param name="directories">
        /// </param>
        private void resolveSubfolders(string[] directories)
        {

            foreach (var dir in directories)
            {
                var tokens = dir.Split('/');

                string folder = String.Empty;

                for (int n = 0; n < tokens.Length; n++)
                {
                    folder = folder + "/" + tokens[n];

                    if (!m_Subfolders.Contains(folder))
                        m_Subfolders.Add(folder);
                }
            }
        }

        /// <summary>
        /// Create folder structure of our web site with all foders. HTML folder must be in root app folder
        /// </summary>
        /// <param name="isolatedStorageFile"></param>
        /// <param name="webResourceFileName"></param>
        /// <returns></returns>
        private string createRequiredDirectory(IsolatedStorageFile isolatedStorageFile, string webResourceFileName)
        {

            string folderPrefix = String.Empty;

            var tokens = webResourceFileName.Split('.');

            string currentFolder = String.Empty;

            for (int n = 0; n < tokens.Length; n++)
            {
                folderPrefix += "/";

                folderPrefix += tokens[n];

                if (m_Subfolders.Contains(folderPrefix))
                {
                    if (!isolatedStorageFile.DirectoryExists(folderPrefix))
                        isolatedStorageFile.CreateDirectory(folderPrefix);

                    currentFolder = folderPrefix.Substring(1);
                }
                else
                {
                    webResourceFileName = String.Empty;

                    bool isFirst = true;

                    for (int i = n; i < tokens.Length; i++)
                    {
                        if (!isFirst)
                            webResourceFileName += ".";
                        else
                            isFirst = false;

                        webResourceFileName += tokens[i];
                    }

                    if (currentFolder != String.Empty)
                        webResourceFileName = currentFolder + "/" + webResourceFileName;

                    break;
                }
            }


            return webResourceFileName;

        }

        /// <summary>
        /// Delete directory of previous version before you install current version is recomended.
        /// We need to go throught all folders and subfolder in order to delete every file.
        /// </summary>
        /// <param name="isolatedStorageFile"></param>
        /// <param name="root"></param>
        private void deleteDirectory(IsolatedStorageFile isolatedStorageFile, string root)
        {
            //First delete all files within currenet folder
            var files = isolatedStorageFile.GetFileNames(root + "/*");
            foreach (var file in files)
            {
                isolatedStorageFile.DeleteFile(root + "/" + file);
                //For debugging proposes
                Debug.WriteLine(root + "/" + file + " deleted!");
            }

            var dirs = isolatedStorageFile.GetDirectoryNames(root + "/*");
            foreach (var dir in dirs)
            {
                //
                if (dir != "Shared")
                {
                    //recursive call of deleteDirectory
                    deleteDirectory(isolatedStorageFile, root + "/" + dir);

                    //at the end of deletion delet empty folder
                    isolatedStorageFile.DeleteDirectory(root + "/" + dir);

                    //For debugging proposes
                    Debug.WriteLine(root + "/" + dir + "Deleted!");
                }
            }
        }

        /// <summary>
        /// Check if the app is running for the first time.
        /// </summary>
        /// <returns></returns>
        private bool IsFirstTimeRun()
        {
           using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                string strFName = "widgetlibraryappcheck.wdg";
                if (!store.FileExists(strFName))
                {
                    // just write simple file with 1 byte
                    using (var stream = store.OpenFile(strFName, FileMode.Create))
                        stream.Write(new byte[] { 1 }, 0, 1);

                    return true;
                }
                else
                    return false;
            }
        }
        #endregion
    }
}
